﻿using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Styx;
using Styx.CommonBot;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace RestoArenaHelper
{
    [UsedImplicitly]
    public static class HealManager
    {
        public const int MaxHealth = 95;
        private const int MaxHealingDistance = 40;
        public const int MaxHealingDistanceSqr = MaxHealingDistance*MaxHealingDistance;
        public static WoWPlayer Tank;
        public static WoWPlayer HealTarget;
        public static WoWPlayer RejuTarget;
        public static WoWPlayer LifeBloomTarget;
        public static Dictionary<WoWPlayer, double> PrioList;
        public static List<WoWObject> huhu;

        public static List<WoWPlayer> GetInitialList
        {
            get { return ObjectManager.GetObjectsOfType<WoWPlayer>().ToList(); }
        }

        public static WoWPlayer GetTank
        {
            get
            {
                // Got a Focus Tank?
                if (StyxWoW.Me.FocusedUnit != null)
                {
                    WoWObject focustank = CachedUnits.HealList.FirstOrDefault(p => p.Guid == StyxWoW.Me.FocusedUnit.Guid);
                    if (focustank != null && focustank.IsValid)
                    {
                        return focustank.ToPlayer();
                    }
                }

                // Using Lazy Raider ?
                if (RaFHelper.Leader != null && RaFHelper.Leader.CurrentHealth > 1 && RaFHelper.Leader != StyxWoW.Me)
                {
                    WoWObject raFHelpertank = CachedUnits.HealList.FirstOrDefault(p => p.Guid == RaFHelper.Leader.Guid);
                    if (raFHelpertank != null && raFHelpertank.IsValid)
                    {
                        return raFHelpertank.ToPlayer();
                    }
                }

                // We in a raid?, lets see if we can get the mainTank as specified by Blizzard (this is decided by iLvL)
                WoWPlayer maintTank =
                    CachedUnits.TankList.FirstOrDefault(p => p.IsAlive && p.IsValid && p.Distance < 40 && p.IsMainTank());

                if (maintTank != null) return maintTank;

                // We in a raid?, Main Tank may be dead, lets get the OffTank.
                WoWPlayer offTank =
                    CachedUnits.TankList.FirstOrDefault(
                        p => p.IsAlive && p.IsValid && p.Distance < 40 && p.IsAssistTank());

                if (offTank != null) return offTank;

                // Hmm ok..we must be in a Party (5 man) lets query the tank by role.
                WoWPlayer partyTank = CachedUnits.TankList.FirstOrDefault(p => p.IsAlive && p.IsValid && p.Distance < 40);
                if (partyTank != null) return partyTank;

                // Damn couldnt find a tank ima be the boss!
                return StyxWoW.Me;
            }
        }

        private static IEnumerable<WoWPartyMember> GroupMembers
        {
            get
            {
                return !StyxWoW.Me.GroupInfo.IsInRaid
                           ? StyxWoW.Me.GroupInfo.PartyMembers
                           : StyxWoW.Me.GroupInfo.RaidMembers;
            }
        }

        internal static List<WoWPlayer> Tanks
        {
            get
            {
                if (!StyxWoW.Me.GroupInfo.IsInParty)
                    return new List<WoWPlayer>();

                return GroupMembers.Where(p => p.HasRole(WoWPartyMember.GroupRole.Tank))
                                   .Select(p => p.ToPlayer())
                                   .Where(p => p != null).ToList();
            }
        }

        public static void PulseHealManager()
        {
            WoWPlayer target =
                CachedUnits.HealList.OrderByDescending(u => WeighFilter(u.ToPlayer())).FirstOrDefault();
            WoWPlayer reju =
                Stuff(CachedUnits.HealList).OrderByDescending(u => WeighFilter(u.ToPlayer())).FirstOrDefault();
            HealTarget = target ?? StyxWoW.Me;
            RejuTarget = reju;
        }

        public static void Initialize()
        {
            PrioList = new Dictionary<WoWPlayer, double>();
        }

        private static double WeighFilter(WoWPlayer p)
        {
            if (p == null) return -500f;
            double prio = p.IsAlive ? 500f : -500f;
            double hp = p.HealthPercent;
            prio -= hp*5;
            if (CachedUnits.TankList.Contains(p) && hp != 100)
            {
                prio += 100f;
            }
            if (hp >= MaxHealth)
                prio -= 500f;
            PrioList[p] = prio;
            return prio;
        }

        private static IEnumerable<WoWPlayer> Stuff(IEnumerable<WoWPlayer> rejuList)
        {
            return rejuList.Where(p => (p.HasMyAura("Rejuvenation") &&
                                        Spell.GetAuraTimeLeft("Rejuvenation", p) < 2) ||
                                       !p.HasMyAura("Rejuvenation"));
        }

        public static bool IsMainTank(this WoWPlayer p)
        {
            if (!GroupMembers.Any()) return false;
            WoWPartyMember partyMember = GroupMembers.FirstOrDefault(pm => pm.Guid == p.Guid);
            bool result = partyMember != null && partyMember.IsMainTank;
            return result;
        }

        public static bool IsAssistTank(this WoWPlayer p)
        {
            if (!GroupMembers.Any()) return false;
            WoWPartyMember partyMember = GroupMembers.FirstOrDefault(pm => pm.Guid == p.Guid);
            bool result = partyMember != null && partyMember.IsMainAssist;
            return result;
        }
    }
}